import pyaudio
import soundfile as sf
import numpy as np
import time
import threading

class AudioInputSimulator:
    def __init__(self):
        self.p = pyaudio.PyAudio()
        self.stream = None
        self.is_playing = False
        
    def list_audio_devices(self):
        """列出所有音频设备"""
        info = self.p.get_host_api_info_by_index(0)
        num_devices = info.get('deviceCount', 0)
        
        # 确保 num_devices 是整数
        if not isinstance(num_devices, int):
            num_devices = 0
        
        print("可用的音频设备:")
        print("输出设备:")
        for i in range(0, num_devices):
            try:
                device_info = self.p.get_device_info_by_host_api_device_index(0, i)
                max_output_channels = device_info.get('maxOutputChannels', 0)
                if isinstance(max_output_channels, (int, float)) and max_output_channels > 0:
                    print(f"  输出设备 ID {i} - {device_info.get('name', 'Unknown')}")
            except Exception as e:
                continue
                
        print("输入设备:")
        for i in range(0, num_devices):
            try:
                device_info = self.p.get_device_info_by_host_api_device_index(0, i)
                max_input_channels = device_info.get('maxInputChannels', 0)
                if isinstance(max_input_channels, (int, float)) and max_input_channels > 0:
                    print(f"  输入设备 ID {i} - {device_info.get('name', 'Unknown')}")
            except Exception as e:
                continue
    
    def find_output_device(self):
        """查找合适的输出设备（用于播放音频）"""
        info = self.p.get_host_api_info_by_index(0)
        num_devices = info.get('deviceCount', 0)
        
        if not isinstance(num_devices, int):
            num_devices = 0
        
        # 查找虚拟音频电缆或类似设备
        for i in range(0, num_devices):
            try:
                device_info = self.p.get_device_info_by_host_api_device_index(0, i)
                max_output_channels = device_info.get('maxOutputChannels', 0)
                device_name = device_info.get('name', '')
                
                if (isinstance(max_output_channels, (int, float)) and max_output_channels > 0 and
                    isinstance(device_name, str)):
                    # 优先查找虚拟音频设备
                    if any(keyword in device_name.lower() for keyword in 
                          ['virtual', 'cable', 'vb-audio', 'voicemeeter', 'line']):
                        return i
            except Exception:
                continue
                
        # 如果没有找到虚拟设备，返回默认输出设备
        try:
            default_output = self.p.get_default_output_device_info()
            return default_output.get('index', 0)
        except Exception:
            return 0
    
    def show_virtual_audio_setup_guide(self):
        """显示虚拟音频设备设置指南"""
        print("=== 虚拟音频设备设置指南 ===")
        print()
        print("要将音频文件作为麦克风输入，您需要安装虚拟音频驱动程序：")
        print()
        print("推荐的虚拟音频驱动：")
        print("1. VB-Audio Virtual Cable (免费)")
        print("   下载地址: https://vb-audio.com/Cable/")
        print("   - 安装后会创建一个虚拟音频设备")
        print("   - 在Windows声音设置中将'CABLE Input'设为默认录音设备")
        print("   - 程序会自动播放音频到'CABLE Input'")
        print()
        print("2. VoiceMeeter (免费)")
        print("   下载地址: https://vb-audio.com/Voicemeeter/")
        print("   - 更强大的虚拟音频混音器")
        print("   - 可以混合多个音频源")
        print()
        print("3. Virtual Audio Cable (付费)")
        print("   下载地址: https://vac.muzychenko.net/")
        print("   - 专业级虚拟音频驱动")
        print()
        print("设置步骤：")
        print("1. 下载并安装虚拟音频驱动")
        print("2. 重启计算机")
        print("3. 在Windows声音设置中：")
        print("   - 将虚拟音频设备设为默认录音设备")
        print("   - 本程序会自动检测并使用虚拟音频设备")
        print("4. 运行本程序播放音频文件")
        print("5. 其他录音软件会将虚拟音频当作麦克风输入")
        print()
        print("注意: 如果没有安装虚拟音频驱动，程序会播放到默认扬声器")
    
    def play_audio_to_virtual_mic(self, wav_file_path, device_index=None, loop=False):
        """将WAV文件播放到虚拟音频设备（可作为麦克风输入）"""
        try:
            # 读取WAV文件
            data, sample_rate = sf.read(wav_file_path, dtype='float32')
            print(f"已读取音频文件: {wav_file_path}")
            print(f"采样率: {sample_rate} Hz, 时长: {len(data)/sample_rate:.2f} 秒")
            
            # 确保是二维数组 (样本, 通道)
            if len(data.shape) == 1:
                data = data.reshape(-1, 1)
            
            # 转换为适当的格式
            audio_data = (data * 32767).astype(np.int16)
            
            # 获取或查找设备索引
            if device_index is None:
                device_index = self.find_output_device()
            
            # 确保设备索引是整数
            if not isinstance(device_index, int):
                device_index = 0
            
            # 获取设备信息
            try:
                device_info = self.p.get_device_info_by_index(device_index)
                device_name = device_info.get('name', 'Unknown')
                print(f"使用输出设备: ID {device_index} - {device_name}")
            except Exception:
                device_name = 'Unknown'
            
            # 打开音频输出流
            self.stream = self.p.open(
                format=pyaudio.paInt16,
                channels=data.shape[1],
                rate=int(sample_rate),
                output=True,
                output_device_index=device_index,
                frames_per_buffer=1024
            )
            
            self.is_playing = True
            print("开始播放音频到虚拟麦克风...")
            print("提示: 如果要作为麦克风输入使用，请:")
            print("1. 安装虚拟音频电缆（如VB-Cable, Virtual Audio Cable等）")
            print("2. 在系统设置中将虚拟电缆设为默认录音设备")
            print("3. 程序会自动选择虚拟音频设备进行播放")
            
            # 播放音频
            def play_audio():
                chunk_size = 1024
                while self.is_playing:
                    # 分块播放音频数据
                    for i in range(0, len(audio_data), chunk_size):
                        if not self.is_playing:
                            break
                        
                        chunk = audio_data[i:i+chunk_size]
                        # 确保chunk的字节数是正确的
                        if chunk.size > 0 and self.stream is not None:
                            self.stream.write(chunk.tobytes())
                        
                        # 稍微延迟以避免缓冲区溢出
                        time.sleep(0.01)
                    
                    if not loop:
                        break
                    print("循环播放...")
                
                self.stop()
            
            # 在新线程中播放音频
            thread = threading.Thread(target=play_audio)
            thread.daemon = True
            thread.start()
            
            return True
            
        except Exception as e:
            print(f"播放错误: {e}")
            import traceback
            traceback.print_exc()
            return False
    
    def stop(self):
        """停止播放"""
        self.is_playing = False
        if self.stream:
            try:
                self.stream.stop_stream()
                self.stream.close()
                self.stream = None
            except Exception as e:
                print(f"停止流时出错: {e}")
        print("已停止播放")
    
    def __del__(self):
        """清理资源"""
        self.stop()
        if hasattr(self, 'p'):
            self.p.terminate()

# 使用示例
if __name__ == "__main__":
    simulator = AudioInputSimulator()
    
    print("=== 虚拟麦克风音频播放器 ===")
    print()
    
    # 显示菜单
    print("请选择操作:")
    print("1. 查看音频设备列表")
    print("2. 查看虚拟音频设备设置指南") 
    print("3. 直接播放音频文件到虚拟麦克风")
    print("4. 退出")
    print()
    
    try:
        choice = input("请输入选择 (1-4): ").strip()
        print()
        
        if choice == "1":
            # 列出所有音频设备
            simulator.list_audio_devices()
            
        elif choice == "2":
            # 显示设置指南
            simulator.show_virtual_audio_setup_guide()
            
        elif choice == "3":
            # 开始播放到虚拟麦克风 (替换为您的WAV文件路径)
            wav_file = "C:\\Users\\masaikk\\Downloads\\sample-12s.wav"
            
            print(f"准备播放文件: {wav_file}")
            print()
            
            # 列出设备以供参考
            simulator.list_audio_devices()
            print()
            
            # 自动选择合适的输出设备并播放
            if simulator.play_audio_to_virtual_mic(wav_file, loop=True):
                try:
                    print()
                    print("播放中... 按Enter键停止")
                    input()
                except KeyboardInterrupt:
                    print("\n收到中断信号")
                finally:
                    simulator.stop()
            else:
                print("无法开始播放")
                print("\n可能的解决方案:")
                print("1. 检查音频文件路径是否正确")
                print("2. 确保安装了 soundfile 和 pyaudio 库")
                print("3. 检查音频设备是否可用")
                print("4. 考虑安装虚拟音频驱动程序")
                
        elif choice == "4":
            print("退出程序")
            
        else:
            print("无效选择，请输入 1-4")
            
    except KeyboardInterrupt:
        print("\n程序被中断")
    except Exception as e:
        print(f"发生错误: {e}")
    finally:
        try:
            simulator.stop()
        except:
            pass